home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989-1999 Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either expressed or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
-
- Programming For Portability and Compatibility
-
- By Bill Koester
-
- In this article I will provide some guidelines for making programs
- portable between the current Amiga models, and hopefully any
- future models. The first rule of compatability is: assume nothing.
- There can be many variations among models and particular user setups.
-
-
- MEMORY
-
- This one should be obvious; the amount of memory varies from one
- Amiga to another. Always check for success when allocating memory.
- If you need to know beforehand, the Exec AvailMem() function can be
- used to provide a means of checking CHIP, FAST, and LARGEST
- memory available during program execution.
-
- FONTS
-
- On floppy based systems, the fonts directory is often deleted by
- the user to get extra disk space. The only fonts you can be
- guaranteed to have are Topaz60 and Topaz80 which reside in ROM.
- If your program can use other fonts, always check for availability first.
- Offer access only to those fonts found in the FONTS directory at run time.
-
-
- DEVICES
-
- Two other files that frequently get deleted are the clipboard.device
- and narrator.device. Check the value returned when you open these devices.
- Of course, you should ALWAYS check for errors when calling any system
- function! If you want to be really friendly, an error message or
- requester is a good idea. Many speech programs won't run because
- the narrator.device or translator.library is not present. This is less
- mysterious if you inform the user of the problem.
-
-
- LIBRARIES
-
- As with devices, never assume the availability of a library. Check
- the value returned by OpenLibrary() calls and notify the user if there
- is a problem. If your program doesn't run and the user doesn't know why,
- you will get the blame (even if the user is at fault).
-
-
- DRIVE UNITS
-
- With the release of the A2000, many disk drive configurations are
- now possible. One configuration often found on the 2000 is one
- internal and one external 3.5" drive. This configuration results
- in drive names of df0: and df2:, NOT df0: and df1: as you might
- expect. With the 2000, there will be many more hard drives, too.
- Remember that additional hard disk partitions or drives have their
- own entry in the mountlist. This means the user has free reign
- over choosing the name. Lots of file requestors allow the user
- to pick df0: or df1: (and possibly ram: or dh0:). Unfortunately,
- very few configure themselves dynamically so that the user can
- pick ANY drive in the run-time system.
-
- So what's the solution? With this article I have included a
- program called getdisks which searches the system for the names
- of all mounted disk devices. The program builds a simple Exec
- List with named nodes. The node names correspond to the names of
- the mounted disk devices. Use this program as a subroutine in
- your application so you can find out what drive units are available.
- For your old applications that can't be changed, try the public domain
- program AssignDev on Fish disk #79.
-
-
-
-
-
-
- /*********************************************************************/
- /* */
- /* Program name: GetDisks (c) 1987-1999 Amiga, Inc. */
- /* */
- /* Function: To find the names of all available disk devices and */
- /* return them to the user in a simple exec list. The */
- /* list is made up of named nodes, the "names" being the */
- /* device name. */
- /* */
- /* Purpose: To provide a way to find out the number of drives */
- /* installed and their names. Provides a method for */
- /* programs to change themselves dynamically according */
- /* to a users particular configuration. */
- /* */
- /* Arguments: None. */
- /* */
- /* Programer: Phillip Lindsay */
- /* */
- /* Revised 24-Aug-87 for Lattice-C Compiler 3.10 (Bill Koester) */
- /*********************************************************************/
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <libraries/filehandler.h>
-
- #ifdef MANX /* Manx includes */
- #include <functions.h>
- #include <stdio.h>
- #else
- #include <lattice/stdio.h>
- #endif
-
- extern struct DosLibrary *DOSBase;
-
- /************************************************************************/
- /* */
- /* NAME */
- /* */
- /* btoc */
- /* */
- /* SYNOPSIS */
- /* */
- /* void btoc(bstring); */
- /* char *bstring; */
- /* */
- /* PURPOSE */
- /* */
- /* To convert the BCPL format string pointed to by bstring, to a */
- /* NULL terminated C string. */
- /* */
- /* INPUTS */
- /* */
- /* char *bstring - Pointer to a string in BCPL format with the */
- /* length in the first byte. */
- /* */
- /* OUTPUTS */
- /* */
- /* None. */
- /* */
- /* RESULTS */
- /* */
- /* The BCPL string (pointed to by bstring) is shifted left one byte */
- /* and the last character is replaced with the NULL terminator */
- /* according to C string format. */
- /* */
- /************************************************************************/
- void btoc(bstring)
- char *bstring;
- {
- register UBYTE len,count,*cstring;
-
- cstring = (UBYTE *) bstring; /* Get pointer to BSTRING */
- len = cstring[0]; /* Length is in first byte */
-
- for(count=0;count < len;count++) /* Shift entire string 1 byte */
- cstring[count] = cstring[count+1]; /* to the left */
-
- cstring[count] = '\0'; /* Replace last byte of BSTR */
- /* with required NULL byte */
- }
-
- /************************************************************************/
- /* */
- /* NAME */
- /* */
- /* GetNode */
- /* */
- /* SYNOPSIS */
- /* */
- /* struct Node *GetNode(name,type,pri) */
- /* char *name; */
- /* UBYTE type,pri; */
- /* */
- /* PURPOSE */
- /* */
- /* GetNode() will build a node structure for you. It will append */
- /* memory to the node structure for the node name passed. */
- /* */
- /* */
- /* INPUTS */
- /* */
- /* char *name - Pointer to C string containg node name. */
- /* UBYTE type - Node type. */
- /* UBYTE pri - Node priority. */
- /* */
- /* OUTPUTS */
- /* */
- /* struct Node * - Pointer to allocated and initialized node. */
- /* Returns NULL on memory allocation error. */
- /* */
- /* RESULTS */
- /* */
- /* Allocates a block of memory big enough for the Node structure */
- /* plus the name string. Copies the name string to the end of the */
- /* block and adjusts ln_Name to point there. Then set ln_Type and */
- /* ln_Pri. Finally returns a pointer to the start of the memory */
- /* block which contains the initialized Node structure with the */
- /* name appended. */
- /* */
- /************************************************************************/
- struct Node *GetNode(name,type,pri)
- char *name;
- UBYTE type,pri;
- {
- register struct Node *mynode;
- register char *myname;
- register UBYTE *mymemory;
- register ULONG mynamesize;
-
- /* Size is 0 if no name else length of string plus NULL terminator */
-
- mynamesize =( ((ULONG)strlen(name)) ? (ULONG)strlen(name)+1 : 0L );
-
- mynode=0; /* make compiler happy about unitialized auto variable */
-
- mymemory = (UBYTE *)
- AllocMem((ULONG)sizeof(*mynode)+mynamesize,MEMF_PUBLIC | MEMF_CLEAR);
-
- if(!mymemory) return((struct Node *)NULL);
-
- mynode = (struct Node *) mymemory;
- if(mynamesize)
- {
- myname = (char *) mymemory+(ULONG)sizeof(*mynode);
- strcpy(myname,name);
- mynode->ln_Name = myname;
- }
- mynode->ln_Type = type;
- mynode->ln_Pri = pri;
-
- return(mynode);
- }
-
- /************************************************************************/
- /* */
- /* NAME */
- /* */
- /* FreeNode */
- /* */
- /* SYNOPSIS */
- /* */
- /* void FreeNode(mynode); */
- /* struct Node *mynode; */
- /* */
- /* PURPOSE */
- /* */
- /* This function assumes you used GetNode() for node initialization. */
- /* Will free all memory used by node. Make sure you remove node from */
- /* any list. */
- /* */
- /* INPUTS */
- /* */
- /* struct Node *mynode - Pointer to a node initialized by GetNode. */
- /* */
- /* OUTPUTS */
- /* */
- /* None. */
- /* */
- /* RESULTS */
- /* */
- /* All memory associated with the node is freed. */
- /* */
- /************************************************************************/
- void FreeNode(mynode)
- struct Node *mynode;
- {
- register ULONG mymemsize;
-
- mymemsize = (ULONG) sizeof(*mynode);
- mymemsize+= ((mynode->ln_Name) ? (ULONG)strlen(mynode->ln_Name)+1 : 0L);
-
- FreeMem(mynode,mymemsize);
- }
-
- /************************************************************************/
- /* */
- /* NAME */
- /* */
- /* getdisks */
- /* */
- /* SYNOPSIS */
- /* */
- /* void getdisks(dlist) */
- /* struct List *dlist; */
- /* */
- /* PURPOSE */
- /* */
- /* This routine searches the system device list for all the disk */
- /* device names. For each disk device found it appends a named node */
- /* to the list pointed to by dlist. The appended node contains the */
- /* name of the disk device as its name. */
- /* */
- /* GLOBALS NEEDED */
- /* */
- /* extern struct DosLibrary *DOSBase; */
- /* */
- /* INPUTS */
- /* */
- /* struct List *dlist; - Pointer to your list to be filled. */
- /* */
- /* OUTPUTS */
- /* */
- /* None. */
- /* */
- /* RESULTS */
- /* */
- /* Named nodes are added to your list where the node names */
- /* correspond to the disk device names currently mounted. */
- /* */
- /************************************************************************/
- void getdisks(dlist)
- struct List *dlist; /* passed a pointer to an initialized exec list */
- {
- extern struct DosLibrary *DOSBase;
- struct RootNode *rnode;
- struct DosInfo *dinfo;
- register struct DeviceNode *dnode;
- register struct Node *adisk;
- char *bname,name[32];
-
- rnode = (struct RootNode *) DOSBase->dl_Root;
- dinfo = (struct DosInfo *) BADDR(rnode->rn_Info);
-
- Forbid();
- for(dnode = (struct DeviceNode *) BADDR(dinfo->di_DevInfo);BADDR(dnode);
- dnode = (struct DeviceNode *) BADDR(dnode->dn_Next))
- {
- if(!dnode->dn_Type && dnode->dn_Task && BADDR(dnode->dn_Name))
- {
- bname = (char *) BADDR(dnode->dn_Name);
- movmem(bname,name,(ULONG)bname[0]+1L);
- btoc(name);
- if((adisk=GetNode(name,0,0))) AddTail(dlist,adisk);
- }
- }
- Permit();
- }
-
- /************************************************************************/
- /* */
- /* NAME */
- /* */
- /* freedisks */
- /* */
- /* SYNOPSIS */
- /* */
- /* void freedisks(dlist) */
- /* struct List *dlist; */
- /* */
- /* PURPOSE */
- /* */
- /* Will free all nodes in the list pointed to by dlist. Assumes the */
- /* nodes where initialized with GetNode(). */
- /* */
- /* INPUTS */
- /* */
- /* struct List *dlist; - Pointer to list with the nodes you want */
- /* freed. */
- /* */
- /* OUTPUTS */
- /* */
- /* None. */
- /* */
- /* RESULTS */
- /* */
- /* All nodes in the list pointed to by dlist are returned to the */
- /* system free memory list. */
- /* */
- /************************************************************************/
- void freedisks(dlist)
- struct List *dlist;
- {
- register struct Node *disk;
-
- while((disk= (struct Node *)RemTail(dlist)))
- FreeNode(disk);
- }
-
- /************************************************************************/
- /* */
- /* M A I N */
- /* */
- /************************************************************************/
- main()
- {
- struct List disks;
- struct Node *disk;
-
- NewList(&disks); /* Initialize list header */
- getdisks(&disks); /* Fill list */
-
- /* print any devices in list.... if any */
- if((struct List *)disks.lh_TailPred != (struct List *)&disks)
- for(disk = disks.lh_Head;disk->ln_Succ;disk=disk->ln_Succ)
- puts(disk->ln_Name);
-
- freedisks(&disks);
- return(0);
- }
-